using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;

namespace WebServiceClientGenerator
{
    /// <summary>
    /// Generate source code of multiple Web Service clients in one source
    /// file.
    /// </summary>
    public class MultiClientGenerator : AbstractClientGenerator
    {
        private readonly IWebServiceConfig _config;

        /// <summary>
        /// Constract a new instance of <see cref="MultiClientGenerator"/>
        /// that generates the source code according to the given
        /// <paramref name="config"/>.
        /// </summary>
        /// <param name="config">
        /// Configuration of what Web Service clients to generate.
        /// </param>
        public MultiClientGenerator(IWebServiceConfig config)
        {
            CodeUtils.CheckArgumentNull(config, "config");
            _config = config;
        }

        /// <summary>
        /// Generate the Web Service client classes and store the source code
        /// in the file specified by <paramref name="filePath"/>.
        /// </summary>
        /// <remarks>
        /// Existing file will be overwritten only when it is different from
        /// the newly generated source code.
        /// </remarks>
        /// <param name="filePath">The file to store the source code.</param>
        public void Generate(string filePath)
        {
            CodeUtils.CheckArgumentNull(filePath, "filePath");
            if(String.IsNullOrEmpty(Path.GetExtension(filePath)))
            {
                filePath = filePath + "." + CodeDomProvider.FileExtension;
            }
            GenerateIfDifferent(filePath);
        }

        /// <summary>
        /// Generate the Web Service client classes and write the source code
        /// to the given <paramref name="writer"/>.
        /// </summary>
        /// <param name="writer">
        /// An instance of <see cref="TextWriter"/> to which the source code
        /// is written.
        /// </param>
        public override void Generate(TextWriter writer)
        {
            CodeUtils.CheckArgumentNull(writer, "writer");

            ICodeGenerator generator = CodeDomProvider.CreateGenerator(writer);
            CodeGeneratorOptions options = CodeGeneratorOptions;

            DisableDocumentationWarning(writer, generator, options);

            // generate the client group
            foreach (IWebServiceGroupConfig group in _config.Groups)
            {
                generator.GenerateCodeFromNamespace(
                    ImplementClientGroup(group), writer, options);
            }

            RestoreDocumentationWarning(writer, generator, options);
        }

        // implements the web service client
        private static CodeNamespace ImplementClientGroup(
            IWebServiceGroupConfig group)
        {
            //Create Namespaces
            CodeNamespace codeNamespace = new CodeNamespace(group.ClientNamespace);
            foreach (IWebServiceClassConfig client in group.Classes)
            {
                CodeTypeDeclaration codeClass = GenerateClassCode(
                    client.ClientClassName, client.XmlNamespace, client.Interfaces);
                codeNamespace.Types.Add(codeClass);
            }
            return codeNamespace;
        }
    }
}
